package upnp

import (
	"encoding/xml"
	"fmt"
	"net/http"
	"strings"
)

// DeletePortMappingAction delete port mapping
type DeletePortMappingAction struct {
	actionData
}

func newDeletePortMappingAction(srv *Service, in, out []string) *DeletePortMappingAction {
	return &DeletePortMappingAction{
		actionData{
			name:  "DeletePortMapping",
			srv:   srv,
			args:  in,
			resps: out,
		},
	}
}

type deletePortMappingBody struct {
	ActionBodyContent
	Host     string `xml:"NewRemoteHost"`
	ExtPort  int    `xml:"NewExternalPort"`
	Protocal string `xml:"NewProtocol"`
}

func (a *DeletePortMappingAction) requestBody(protocal string, port int) (*actionBodyType, error) {
	body := new(deletePortMappingBody)
	body.Init(a.actionData)
	body.ExtPort = port
	body.Protocal = protocal
	return newActionBody(body)
}

type deletePortMappingResponse struct {
	Code   string `xml:"Body>Fault>faultcode"`
	String string `xml:"Body>Fault>faultstring"`
	Detail struct {
		UPnPError struct {
			Code        int    `xml:"errorCode"`
			Description string `xml:"errorDescription"`
		} `xml:"UPnPError"`
	} `xml:"Body>Fault>detail"`
}

// Do delete port mapping
func (a *DeletePortMappingAction) Do(protocal string, port int) (*ActionResponse, error) {
	obj, err := a.requestBody(protocal, port)
	if err != nil {
		return nil, err
	}
	bodyData, err := xml.Marshal(obj)
	if err != nil {
		return nil, err
	}
	data := xml.Header + string(bodyData)
	resp, err := a.sendRequest(strings.NewReader(data), len(data))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusOK {
		return &ActionResponse{}, nil
	}
	var ret deletePortMappingResponse
	if err := xml.NewDecoder(resp.Body).Decode(&ret); err != nil {
		return nil, err
	}
	return nil, fmt.Errorf("DeletePortMapping failed: %d/%s",
		ret.Detail.UPnPError.Code, ret.Detail.UPnPError.Description)
}
